//--------------------------------------进阶篇------------------------------------------------------

/*
     【 一、类型操作符（Type Operators）】
        用于动态操作类型，是源码中泛型和工具类型的基础。
   ------------------------------------------------------------------------------
*/


/*
    1. keyof ：获取对象键的联合类型
        用途 ：提取对象属性名的类型，常用于泛型约束（如封装通用工具函数）。 
        源码场景 ：Vue3 的 Ref 类型、React 的 ComponentProps 均用此操作符。
   -----------------------------------------------------------------------------------------
*/
interface User {
  name: string;
  age: number;
}

type UserKeys = keyof User; // "name" | "age"

// 泛型函数：根据键获取对象值
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key];
}

// const user: User = { name: "Alice", age: 30 };
// const userName = getProperty(user, "name"); // 类型：string


/*
    2.typeof ：从值推断类型
        用途 ：从变量或对象实例反向推导类型，避免重复定义。 
        源码场景 ：Redux 的 ActionCreator 类型、Vue 的 DefineComponent 均用此特性。
   -----------------------------------------------------------------------------------------    
*/
const config = {
  apiUrl: "https://api.example.com",
  timeout: 5000
};

type ConfigType = typeof config;
// 等价于 { apiUrl: string; timeout: number }

// 结合 keyof 提取键类型
type ConfigKeys = keyof typeof config;  // "apiUrl" | "timeout"


/*
    3.infer ：在条件类型中推断类型
        用途 ：从泛型参数中提取子类型（如函数返回值、数组元素类型）。 
        源码场景 ：Lodash 的 ReturnType 、RxJS 的 Observable 类型均依赖此特性。
   -----------------------------------------------------------------------------------------
*/
// 提取函数返回值类型
// type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never;

// 提取数组元素类型
type ArrayElementType<T> = T extends (infer E)[] ? E : never;

// 示例
type AddFn = (a: number, b: number) => number;
type AddResult = ReturnType<AddFn>; // number

type StringArray = string[];
type StringType = ArrayElementType<StringArray>; // string


/*
     【 二、高级类型（Advanced Types）】
        通过组合基础类型生成动态类型，是源码中复杂类型设计的核心。
   ------------------------------------------------------------------------------
*/

/*
    1. 条件类型（Conditional Types）
        用途 ：根据类型关系动态选择类型（类似三元表达式）。 
        源码场景 ：React 的 PropsWithChildren 、TypeScript 内置的 Exclude 均基于此实现。
   -----------------------------------------------------------------------------------------
*/
// 内置工具类型 Exclude<T, U>：排除 T 中可分配给 U 的类型
// type Exclude<T, U> = T extends U ? never : T;
type A1 = "a" | "b" | "c";
type B1 = "a" | "d";
type Result = Exclude<A, B>;  // "b" | "c"

// 自定义：判断是否为数组类型
type IsArray<T> = T extends any[] ? true : false;
type IsStringArray = IsArray<string[]>; // true
type IsNumber = IsArray<number>; // false


/*
    2. 映射类型（Mapped Types）
        用途 ：遍历已有类型的键，生成新类型（如将所有属性变为可选/只读）。
         源码场景 ：TypeScript 内置的 Partial<T> 、 Readonly<T>     ，Vue 的 ComputedRef 均用此实现。
   -----------------------------------------------------------------------------------------
*/
// 内置工具类型 Partial<T>：将所有属性变为可选
// type Partial<T> = { [P in keyof T]?: T[P] };

// 自定义：深度只读类型（源码中常见的嵌套对象处理）
type DeepReadonly<T> = T extends object
  ? { readonly [P in keyof T]: DeepReadonly<T[P]> }
  : T;

type NestedObj = { a: number; b: { c: string } };
type ReadonlyNestedObj = DeepReadonly<NestedObj>;
// { readonly a: number; readonly b: { readonly c: string } }


/*
    3. 模板字面量类型（Template Literal Types）
        用途 ：基于字符串字面量生成新类型（如事件名、CSS 类名）。
        源码场景 ：Vue 的 Emit 类型、React 的 HTMLAttributes 均用此定义事件类型。
   -----------------------------------------------------------------------------------------
*/
type EventName = `on${string}Event`;
type ClickEvent = EventName; // "onClickEvent" | "onHoverEvent" 等

// 结合联合类型生成具体事件
type Direction = "top" | "bottom" | "left" | "right";
type PositionClass = `position-${Direction}`;
// "position-top" | "position-bottom" | "position-left" | "position-right"


/*
     【 三、装饰器（Decorators）】
        用途 ：元编程工具，用于修改类、方法、属性的行为（需启用 experimentalDecorators 编译选项）。 
        源码场景 ：NestJS 的 @Controller 、 @Injectable ，Angular 的 @Component 均基于装饰器实现
   ------------------------------------------------------------------------------
*/


/*
    1. 类装饰器
   -----------------------------------------------------------------------------------------
*/
// 为类添加元数据
function LogClass(target: Function) {
  console.log(`类 ${target.name} 被创建`);
  target.prototype.className = target.name; // 为原型添加属性
}

// @LogClass
class UserService {
  getUserName() {
    return "Alice";
  }
}

const service = new UserService();
// console.log(service.className); // "UserService"（装饰器添加的属性）

/*
    2. 方法装饰器
   -----------------------------------------------------------------------------------------
*/
// 记录方法调用日志
function LogMethod(target: any, methodName: string, descriptor: PropertyDescriptor) {
  const originalMethod = descriptor.value;
  descriptor.value = function(...args: any[]) {
    console.log(`调用方法 ${methodName}，参数：${JSON.stringify(args)}`);
    return originalMethod.apply(this, args);
  };
  return descriptor;
}

class Calculator {
//   @LogMethod
  add(a: number, b: number) {
    return a + b;
  }
}

const calc = new Calculator();
calc.add(1, 2); // 输出："调用方法 add，参数：[1,2]"



/*
     【 四、声明文件与类型声明（ .d.ts ）】
        用途 ：为 JavaScript 库或无类型代码提供类型定义，是集成第三方库的关键。
        源码场景 ：所有第三方库（如 lodash 、 axios ）的类型声明均通过 .d.ts 文件提供。
      详细描述：
            1.为 JavaScript 库提供类型支持
                  当您使用纯 JavaScript 编写的库（如 jQuery、Lodash）时，.d.ts 文件可以为这些库添加类型注解，让 TypeScript 能识别其 API 的类型
            2.全局类型扩展
                  通过 .d.ts 文件，您可以扩展全局类型（如 window、Promise）或声明全局变量（如 process.env）。
            3.模块类型声明
                  声明第三方模块或自定义模块的导出类型，避免直接修改模块源码。
            4.环境类型声明
                  声明浏览器或 Node.js 环境中的全局 API（如 document、fetch）。

      如何使用：

         1. 创建文件(推荐将类型文件放在 types 目录或 src 目录下)   types/xxx.d.ts
         2. 配置 tsconfig.json (确保 TypeScript 能识别类型文件)
            {
               "compilerOptions": {
                  "typeRoots": ["./node_modules/@types", "./types"]
               }
            }
            // typeRoots 指定类型文件的搜索路径 (默认会包含 node_modules/@types（存放第三方库的类型）。)
          3.使用 declare 关键字
               declare module：声明模块类型。
               declare global：扩展全局类型。
               declare const / declare interface：声明变量或接口。

      如何获取第三方库：
         npm install --save-dev @types/xxx
   ------------------------------------------------------------------------------
*/

//  1.为 JavaScript 库添加类型
// axios.d.ts（为 axios 补充类型）
declare module "axios" {
  interface AxiosInstance {
    $get<T>(url: string): Promise<T>; // 扩展 axios 实例方法
  }
}
// // 假如你有一个没有类型声明的JS库 myLib， 可以手动创建一个 myLib.d.ts 文件来声明它的类型：
// declare module "myLib" {
//    export const version: string;
//    export function greet(name: string): string; // 声明模块导出的函数
// }
// // 然后在代码中直接使用
// import { greet } from "myLib";
// console.log(greet('TypeScript')); // 类型安全


// 2. 扩展全局类型  global.d.ts
declare const VERSION: string; // 声明全局变量（如打包工具注入的版本号）
declare function greet(name: string): string; // 声明全局函数

// declare global {
//    interface Window{
//       myCustomerProperty: string; // 扩展全局 window 的属性

//    }
// }
// 使用时无需导入
// window.myCustomProperty = 'hello';


//3.声明全局变量 在 env.d.ts 中声明环境变量：
declare namespace NodeJS {
  interface ProcessEnv {
    API_KEY: string;
    NODE_ENV: 'development' | 'production'; // 扩展 process.env 的类型
  }
}

// 使用时
console.log(process.env.API_KEY); // 类型提示
console.log(process.env.NODE_ENV); // 类型提示

//4. 声明模块类型 (对于未导出的模块（如通过 <script> 引入的库），使用 declare：)
// jquery.d.ts
declare const $: {
   (selector: string): JQuery;
   ajax(url: string, options?: any): Promise<any>;
}

declare interface JQuery {
    html(content: string): void;
}


/*
     【 五、编译选项与工程配置（ tsconfig.json ）】
        用途 ：控制类型检查严格度、输出代码格式，是大型项目的核心配置。
   ------------------------------------------------------------------------------
   关键配置项示例：
   -----------------------------------------------------------------------------------------
   {
      "compilerOptions": {
         "strict": true, // 启用所有严格检查（必开）
         "target": "ESNext", // 输出 ECMAScript 版本
         "module": "ESNext", // 模块系统
         "moduleResolution": "Node", // 模块解析策略（Node.js 风格）
         "esModuleInterop": true, // 兼容 CommonJS 和 ES 模块
         "skipLibCheck": true, // 跳过第三方库类型检查（提升编译速度）
         "forceConsistentCasingInFileNames": true, // 强制文件名大小写一致（避免跨平台问题）
         "types": ["node"], // 自动包含的类型声明文件
         "baseUrl": ".", // 解析非相对路径的基础目录
         "paths": {
            "@/*": ["src/*"] // 路径映射（如 @/components 指向 src/components）
         }
      }
   }
*/


/*
 【 六、源码阅读高频工具类型（附实现）】
       源码中常见的工具类型，理解它们是阅读框架（如 React、Vue）的关键
   ------------------------------------------------------------------------------
*/
// 1. NonNullable<T> ：排除 null 和 undefined
// type NonNullable<T> = T & {}; // 等价于 T extends null | undefined ? never : T
type MaybeString = string | null | undefined;
type ValidString = NonNullable<MaybeString>; // string

//2. Record<K, T> ：键为 K、值为 T 的对象类型
// type Record<K extends keyof any, T> = { [P in K]: T };
type UserMap = Record<string, User>; // { [key: string]: User }

//3. Omit<T, K> ：排除 T 中的 K 属性（与 Pick 相反）
// type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
type UserWithoutAge = Omit<User, "age">; // { name: string }












/*
 
   -----------------------------------------------------------------------------------------
*/



/*
 
   -----------------------------------------------------------------------------------------
*/



/*
 
   -----------------------------------------------------------------------------------------
*/

